﻿using System;
using System.Net;
using System.IO;
using System.Windows;
using Newtonsoft.Json;
using System.Windows.Controls;

namespace FlyComet.Silverlight
{
    public class FlyCometSilverlight
    {
        static String flycometClientId;
        public delegate void ConnectionDelegate(bool connected);
        public delegate void LiveUpdateDelegate(LiveMessage message);
        public event ConnectionDelegate Connected;
        private readonly long ping_interval = 30000;
        public event LiveUpdateDelegate LiveUpdateReceived;
        private UserControl control;
        private static bool isConnected=false;
        private static DateTime LastRequestTime = DateTime.MinValue;
        System.Threading.Timer timer = null;
        private static Object lockObject = new object();

        public FlyCometSilverlight(UserControl p_control)
        {
            control = p_control;
            if (timer == null)
                timer = new System.Threading.Timer(Timer_Elapsed, null, 0, ping_interval);
        }

        void Timer_Elapsed(object userstate)
        {
            try
            {
                if (isConnected && DateTime.Now > LastRequestTime.AddSeconds(15))
                {
                    RequestUpdates();
                }
            }
            catch (Exception ex)
            {
            }
        }

        public bool Connect()
        {
            control.Dispatcher.BeginInvoke(delegate()
            {
                HttpWebRequest myRequest = WebRequest.CreateHttp(GetFlyCometHandlerUrl("connect", ""));
                myRequest.Method = "GET";
                myRequest.BeginGetResponse(GetResponseCallback, myRequest);
            });
            return true;
        }

        public bool DisConnect()
        {
            control.Dispatcher.BeginInvoke(delegate()
            {
                HttpWebRequest myRequest = WebRequest.CreateHttp(GetFlyCometHandlerUrl("disconnect", ""));
                myRequest.Method = "GET";
                myRequest.BeginGetResponse(GetResponseCallback, myRequest);
            });
            return true;
        }

        public bool Subscribe(String topic)
        {
            HttpWebRequest myRequest = WebRequest.CreateHttp(GetFlyCometHandlerUrl("subscribe", topic));
            myRequest.Method = "GET";
            myRequest.BeginGetResponse(GetResponseCallback, myRequest);
            return true;
        }

        public void RequestUpdates()
        {
            System.Threading.Thread.Sleep(2000);
            lock (lockObject)
            {
                LastRequestTime = DateTime.Now;
            }
            control.Dispatcher.BeginInvoke(delegate()
            {
                HttpWebRequest myRequest = WebRequest.CreateHttp(GetFlyCometHandlerUrl("receive", ""));
                myRequest.Method = "GET";
                myRequest.BeginGetResponse(GetResponseCallback, myRequest);
            });
        }

        private String GetFlyCometHandlerUrl(String command, String topic)
        {
            int index = Application.Current.Host.Source.AbsoluteUri.IndexOf(Application.Current.Host.Source.AbsolutePath);
            String returnHostUrl = "";
            switch (command)
            {
                case "connect":
                    returnHostUrl = String.Format("{0}FlyCometHandler.ashx?command={1}", Application.Current.Host.Source.AbsoluteUri.Remove(index + 1), command);
                    break;
                case "disconnect":
                    returnHostUrl = String.Format("{0}FlyCometHandler.ashx?command={1}&requestkey={2}", Application.Current.Host.Source.AbsoluteUri.Remove(index + 1), command, flycometClientId);
                    break;
                case "subscribe":
                    returnHostUrl = String.Format("{0}FlyCometHandler.ashx?command={1}&requestkey={2}&channel={3}", Application.Current.Host.Source.AbsoluteUri.Remove(index + 1), command, flycometClientId, topic);
                    break;
                case "unsubscribe":
                    returnHostUrl = String.Format("{0}FlyCometHandler.ashx?command={1}&requestkey={2}&channel={3}", Application.Current.Host.Source.AbsoluteUri.Remove(index + 1), command, flycometClientId, topic);
                    break;
                case "receive":
                    returnHostUrl = String.Format("{0}FlyCometHandler.ashx?command={1}&requestkey={2}", Application.Current.Host.Source.AbsoluteUri.Remove(index + 1), command, flycometClientId);
                    break;

            }
            return returnHostUrl;
        }


        private void GetResponseCallback(IAsyncResult asynchronousResult)
        {
            try
            {
                HttpWebRequest request = (HttpWebRequest)asynchronousResult.AsyncState;
                WebResponse resp = request.EndGetResponse(asynchronousResult);
                HttpWebResponse response = (HttpWebResponse)resp;
                Stream streamResponse = response.GetResponseStream();
                StreamReader streamRead = new StreamReader(streamResponse);
                string responseString = streamRead.ReadToEnd();
                // Close the stream object
                streamResponse.Close();
                streamRead.Close();
                // Release the HttpWebResponse
                response.Close();

                LiveMessage livemsg = JsonConvert.DeserializeObject<LiveMessage>(responseString);
                if (livemsg.StatusCode == 0 && request.RequestUri.AbsoluteUri.Contains("receive"))
                {
                    flycometClientId = livemsg.RequestId;
                    if (LiveUpdateReceived != null)
                        LiveUpdateReceived(livemsg);
                }
                else if (request.RequestUri.AbsoluteUri.Contains("connect"))
                {
                    isConnected = true;
                    flycometClientId = livemsg.RequestId;
                    if (Connected != null)
                        Connected(true);
                }
            }
            catch (Exception e)
            {
            }

            if (isConnected && DateTime.Now > LastRequestTime.AddSeconds(2))
                RequestUpdates();
        }
    }
}
